﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	SqlQueryBuilderItemGroup.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System.Collections.Generic;
using System.Linq;

namespace Smart.Common.Entities
{
	/// <summary>
	/// Query item group
	/// </summary>
	public abstract class SqlQueryBuilderItemGroup<TExecutorType> : SqlQueryBuilderItem<TExecutorType>
		where TExecutorType : class
	{
		/// <summary>
		/// Children
		/// </summary>
		public List<SqlQueryBuilderItem<TExecutorType>> Children { get; set; }

		/// <summary>
		/// QueryBuilder Query Items group
		/// </summary>
		/// <param name="op">Group operation</param>
		protected SqlQueryBuilderItemGroup(string op)
			: base(op)
		{
			Children = new List<SqlQueryBuilderItem<TExecutorType>>();
		}

		/// <summary>
		/// QueryBuilder Query Items group
		/// </summary>
		/// <param name="op">Group operation</param>
		/// <param name="items">Items</param>
		protected SqlQueryBuilderItemGroup(string op, IEnumerable<SqlQueryBuilderItem<TExecutorType>> items)
			: base(op)
		{
			Children = new List<SqlQueryBuilderItem<TExecutorType>>(items);
		}

		/// <summary>
		/// Create new group
		/// </summary>
		public abstract SqlQueryBuilderItemGroup<TExecutorType> Create();

		/// <summary>
		/// Add child items and update their props
		/// </summary>
		/// <param name="items"></param>
		public void AddItems(IEnumerable<SqlQueryBuilderItem<TExecutorType>> items)
		{
			Children.AddRange(items);

			SetChildrenProps();
		}

		/// <summary>
		/// Add item
		/// </summary>
		public void AddItem(SqlQueryBuilderItem<TExecutorType> builderItem)
		{
			builderItem.Query = Query;
			builderItem.Group = this;

			Children.Add(builderItem);
		}

		public List<IQueryBuilderItem<TExecutorType>> FindRecursive(string op)
		{
			var res = new List<IQueryBuilderItem<TExecutorType>>();

			foreach (var item in Children)
			{
				if (item.Op.EqIC(op))
				{
					res.Add(item);
					continue;
				}

				var group = item as SqlQueryBuilderItemGroup<TExecutorType>;

				if (group != null)
					res.AddRange(group.FindRecursive(op));
			}

			return res;
		}

		/// <summary>
		/// Set for all Children QueryBuilder and Group properties
		/// </summary>
		public void SetChildrenProps()
		{
			foreach (var item in Children)
			{
				item.Query = Query;
				item.Group = this;
			}
		}

		/// <summary>
		/// Set for all Children QueryBuilder and Group properties
		/// </summary>
		public void SetChildrenProps(IEnumerable<SqlQueryBuilderItem<TExecutorType>> childrenEnumerable)
		{
			foreach (var item in childrenEnumerable)
			{
				item.Query = Query;
				item.Group = this;
			}
		}

		/// <summary>
		/// Format QueryBuilder statement
		/// </summary>
		public override string FormatQuery()
		{
			var items = Children.Where(item => item != null);

			var filters = items.CastToString(" " + Op + " ", item => item.FormatQuery());

			return filters.IsNullOrEmpty() ? string.Empty : "(" + filters + ")";
		}

		/// <summary>
		/// Return Cache key
		/// </summary>
		public virtual string GetCacheKey()
		{
			return GetCacheCode().ToStringX();
		}

		/// <summary>
		/// Return Cache code
		/// </summary>
		public override int GetCacheCode()
		{
			var res = Op.GetHashCode() ^ Children.Count.GetHashCode();

			return Children.Aggregate(res, (current, child) => current ^ child.GetCacheCode());
		}
	}
}